﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace FuncCandels
{
    public class CandelsData
    {


        public static DataTable GetMACDTable(DataTable Candles, int Short_, int Long_, int MACDsglag, string variant)
        {
            //1.  Линейный MACD   
            //Для расчета линейного MACD из скользящей средней цены (обычно берется экспоненциальная скользящая средняя) с меньшим периодом вычитается 
            //экспоненциальная средняя с большим периодом. В большинстве случаев полученный результат сглаживают при помощи экспоненциальной скользящей 
            //средней (ЕМА), чтобы устранить случайные колебания. 
            //MACD =  (ЕМАl(P)-EMAs(P)),
            // Signal =  ЕМАa (ЕМАl(P)-EMAs(P)),
            //Где: 
            // ЕМАl(P)-  экспоненциальная скользящая средняя с длинным периодом  от цены.
            // EMAs(P)-  экспоненциальная скользящая средняя с коротким периодом от цены
            // ЕМАa(P)– сглаживающая экспоненциальная скользящая средняя с коротким периодом от разницы двух остальных скользящих.  
            // P – цена, обычно берется цена закрытия периода Close, но возможны и другие варианты (Open, High, Low, Close, Median Price, Typical Price и т.д.) 
            //По умолчанию обычно берутся следующие настойки MACD: 
            // ЕМАs  (короткая) с периодом 12 (две недели)
            // ЕМАl  (длинная) с периодом 26 (месяц)
            // ЕМАa  (сглаживающая разницу) с периодом 9
            //2.  Формула  MACD гистограммы
            //Для использованиия  MACD гистограммы необходимо вычесть сигнальную линию из линии MACD. 
            //MACD гистограмма = MACD – Signal. 
            //Комментарии: в современных учебниках находящихся в Интернет, да и во многих новых публикациях существует путаница между описаниями индикатора 
            //MACD и MACD гистограммы. Путаница вызвана одинаковыми названиями индикатора «MACD-гистограммы» и способа отображения линейной MACD в виде гистограммы.  
            
            //DataTable myTable = Candles;
            // Set PrimaryKey
            //myTable.Columns["id"].Unique = true;
            //myTable.PrimaryKey = new DataColumn[] { myTable.Columns["id"] };


                //В QUIK ормула экспоненциальной скользящей средней 
                //Мы уточнили формулу расчёта первого члена у разработчиков, выяснилось, 
                //расчёт цены идёт не совсем так , как мы описали ранее. 
                //Механизм продемонстрируем на Вашем примере:
                //N=5
                //P1=77825
                // P2=77825
                // P3=77825
                // P4=77800
                // P5=77800
                //Е1 = Р1 = 77825
                //Е2 =(Е1*(5–1)+2*Р2)/(5+1)= = 77825
                //Е3=(Е2*(5–1)+2*Р3)/(5+1).....=77825
                //Е4=(Е3*(5–1)+2*Р4)/(5+1) = 77816,6667
                //Е5=(Е4*(5–1)+2*Р5)/(5+1) = 77811,1111
                //Таким образом, в качестве первого значения в формуле экспонициальной скользящей средней 
                //берётся первое значение. (По умолчанию берётся параметр цена закрытия).
                //Отображение графика начнётся с точки Е5 = 77811,1111. Что вы собственно и наблюдали.

            //EMA(n) = k * P(n) + (1-k) * EMA(n-1)
            //и k=2/(26+1) = 0.074074074074074074074074074074074
            

            DataRow[] myRows;
            myRows = Candles.Select();

            Candles.Columns.Add("EMAL", typeof(double));
            Candles.Columns.Add("EMAS", typeof(double));
            Candles.Columns.Add("MACD", typeof(double));
            Candles.Columns.Add("MACDS", typeof(double));
            Candles.Columns.Add("MACDG", typeof(double));

            double EMAL_1, EMAS_1, Pt, MACD_1,summMACD;

            for (int i = myRows.Length - 1; i >= 0; i--)
            {
                if (i < myRows.Length - 1)        // расчет ЕМА        
                {//EMA = EMA(t-1) + (2/(n+1))*(Pt - EMA(t-1)), где Pt - текущая котировка; n - период усреднения.
                    EMAL_1 = (Double)myRows[i + 1]["EMAL"];
                    EMAS_1 = (Double)myRows[i + 1]["EMAS"];
                    Pt = System.Convert.ToDouble(myRows[i][variant]);
                    myRows[i]["EMAL"] = (EMAL_1 * (Long_-1) + 2.0*Pt) / (Long_ + 1);//EMA с длинным периодом;
                    myRows[i]["EMAS"] = (EMAS_1 * (Short_-1) + 2.0 * Pt) / (Short_ + 1);//EMA с коротким периодом
                    //myRows[i]["MACD"] = (Double)myRows[i]["EMAS"] - (Double)myRows[i]["EMAL"]; //MACD 
                    myRows[i]["MACD"] = (1-(Double)myRows[i]["EMAL"] /(Double)myRows[i]["EMAS"])*100; //MACD 
                    myRows[i]["MACDS"] = 0.0;
                    myRows[i]["MACDG"] = 0.0;
                    if (i < myRows.Length - ( MACDsglag))
                    {
                        MACD_1 = (Double)myRows[i + 1]["MACDS"];
                        Pt = (Double)(myRows[i]["MACD"]);
                        // myRows[i]["MACDSignal"] = (MACD_1 * (MACDsglag - 1) + 2.0 * Pt) / (MACDsglag + 1);//Сглаживаем MACD, получаем сам сигнл макд, сглаживание по EMA
                        summMACD = 0.0;
                        for (int j = 0; j <= MACDsglag-1; j++)
                        {
                            summMACD +=     (Double)myRows[i+j]["MACD"];
                        }
                        myRows[i]["MACDS"] = summMACD/ MACDsglag; //(MACD_1 * (MACDsglag - 1) + 2.0 * Pt) / (MACDsglag + 1);//Сглаживаем MACD, получаем сам сигнл макд, сглаживание по SMA
                            //myRows[i]["MACDL"] = MACD_1 + (2.0 / (MACDsglag + 1)) * (Pt - MACD_1);//Сглаживаем MACD, получаем сам сигнл макд, сглаживание по EMA
                        myRows[i]["MACDG"] = (Double)(myRows[i]["MACD"]) - (Double)myRows[i]["MACDS"];//получаем гистограмму   

                    }
                    else { myRows[i]["MACDS"] = myRows[i]["MACD"]; }
                }
                else
                {

                    myRows[i]["EMAL"] = myRows[i][variant];
                    myRows[i]["EMAS"] = myRows[i][variant];
                    myRows[i]["MACD"] = 0.0; 
                    myRows[i]["MACDG"] = 0.0; 
                    myRows[i]["MACDS"] = 0.0;
                }
            }
            //myTable.DefaultView.Sort = "id"; //сортируем таблицу по id

           // string strExpr;
           // string strSort;
           // strExpr = "MACDG > 0";
            // Sort descending by column named CompanyName.
            //strSort = "id DESC";
            //DataRow[] foundRows;
            // Use the Select method to find all rows matching the filter.
           // myRows = Candles.Select(strExpr, strSort);
            // Print column 0 of each returned row.
            //for (int i = 0; i < foundRows.Length; i++)
            //{
            //    Console.WriteLine(foundRows[i][0]);
            //}

            return Candles;
        }

        public static DataTable GetQuikCandles(string Seccode, string Per, string seccode_trans, string DateStart, string DateFinish, string TimeFinish)
        {
            DataTable MyTable = new DataTable();
            MySql.Data.MySqlClient.MySqlConnection conn;
            MySql.Data.MySqlClient.MySqlCommand cmd;
            MySql.Data.MySqlClient.MySqlDataAdapter myAdapter;

            conn = new MySql.Data.MySqlClient.MySqlConnection();
            cmd = new MySql.Data.MySqlClient.MySqlCommand();
            myAdapter = new MySql.Data.MySqlClient.MySqlDataAdapter();

            conn.ConnectionString = "server=92.255.251.110;uid=ast;pwd=7hxSAYcrYCjn7nb5;database=pager;";
            //conn.ConnectionString = "server=localhost;uid=ast;pwd=7hxSAYcrYCjn7nb5;database=pager;";
            cmd.Connection = conn;

            cmd.CommandText = "SELECT * FROM history_quik where " + 
                            "date >= " + DateStart +
                            //  " and time >=" + TimeStart +
                            //" and date <=" + DateFinish + and time <=" + TimeFinish + 
                            " and ((date*1000000 + time)<= '" + DateFinish + TimeFinish + "')" +
                            //AND ((date & time)<='20111115213500')
                            " and "+
                            " per = '" + Per + "' and seccode = '" + Seccode +
                            
                            "' ORDER BY date DESC, time DESC";

            myAdapter.SelectCommand = cmd;
            myAdapter.Fill(MyTable);

            // Add columns 
            MyTable.Columns.Add("id", typeof(int));

            MyTable.Columns.Add("typical", typeof(double));
            
            MyTable.Columns.Add("median", typeof(double));
            MyTable.Columns.Add("ticker", typeof(string));

            int i = 1;
            // заполняем id в обратном порядке чтобы последняя свеча была 1ой
            // нулевая свеча - не дорисованная (пока в разработке, на данный момент 0 - это последняя дорисованная) 

            //foreach (DataRow row in MyTable.Rows)
            //{
            //    row["id"] = MyTable.Rows.Count - i;
            //    row["typical"] = (System.Convert.ToDouble(row["high"]) + System.Convert.ToDouble(row["low"]) + System.Convert.ToDouble(row["close"])) / 3;
            //    row["median"] = (System.Convert.ToDouble(row["high"]) + System.Convert.ToDouble(row["close"])) / 2;
            //    i++;
            //}
            i = 0;
            foreach (DataRow row in MyTable.Rows)
            {
                row["id"] = i;
                row["typical"] = (System.Convert.ToDouble(row["high"]) + System.Convert.ToDouble(row["low"]) + System.Convert.ToDouble(row["close"])) / 3;
                row["median"] = (System.Convert.ToDouble(row["high"]) + System.Convert.ToDouble(row["close"])) / 2;
                row["ticker"] = row["seccode"];
               // row["ticker"] = seccode_trans;//row["seccode"];

                i = i + 1;
            }
            //Set PrimaryKey

            MyTable.Columns["id"].Unique = true;
            MyTable.PrimaryKey = new DataColumn[] { MyTable.Columns["id"] };
            MyTable.DefaultView.Sort = "id"; //сортируем таблицу по id

            return MyTable;
        }

        public static DataTable GetCandles(string Seccode, string Per, string DateStart, string DateFinish)
        {
            DataTable MyTable = new DataTable();
            MySql.Data.MySqlClient.MySqlConnection conn;
            MySql.Data.MySqlClient.MySqlCommand cmd;
            MySql.Data.MySqlClient.MySqlDataAdapter myAdapter;

            conn = new MySql.Data.MySqlClient.MySqlConnection();
            cmd = new MySql.Data.MySqlClient.MySqlCommand();
            myAdapter = new MySql.Data.MySqlClient.MySqlDataAdapter();

            conn.ConnectionString = "server=92.255.251.110;uid=ast;pwd=7hxSAYcrYCjn7nb5;database=pager;";
            //conn.ConnectionString = "server=localhost;uid=ast;pwd=7hxSAYcrYCjn7nb5;database=pager;";
            cmd.Connection = conn;

            cmd.CommandText = "SELECT * FROM ticker where date >= " + DateStart +
                          //  " and time >=" + TimeStart +
                            " and date <=" + DateFinish +                            
                            //" and time <=" + TimeFinish + 
                           // " and time <=" + "'113000'" + 
                            " and per = " + Per + 
                            " and ticker = '" + Seccode + 
                            "'";            

            myAdapter.SelectCommand = cmd;
            myAdapter.Fill(MyTable);

            // Add columns 
            MyTable.Columns.Add("id", typeof(int));

            MyTable.Columns.Add("typical", typeof(double));
            MyTable.Columns.Add("median", typeof(double));

            int i = 1;
            // заполняем id в обратном порядке чтобы последняя свеча была 1ой
            // нулевая свеча - не дорисованная (пока в разработке, на данный момент 0 - это последняя дорисованная) 

            foreach (DataRow row in MyTable.Rows)
            {
                row["id"] = MyTable.Rows.Count - i;
                row["typical"] = (System.Convert.ToDouble(row["high"]) + System.Convert.ToDouble(row["low"]) + System.Convert.ToDouble(row["close"])) / 3;
                row["median"] = (System.Convert.ToDouble(row["high"]) + System.Convert.ToDouble(row["close"])) / 2;
                i++;
            }



            //Set PrimaryKey

            MyTable.Columns["id"].Unique = true;
            MyTable.PrimaryKey = new DataColumn[] { MyTable.Columns["id"] };
            MyTable.DefaultView.Sort = "id"; //сортируем таблицу по id

            return MyTable;
        }

       
    }
}
